#include "stm32f10x.h"
#include "USART.h"

/*------------- 硬件引脚配置宏 ------------------*/
#define UART_TX_PIN   GPIO_Pin_9  	// USB 的 RXD（接收数据）引脚需要连接到 MCU 的 TX（发送数据）引脚
#define UART_RX_PIN   GPIO_Pin_10   // USB 的 TXD（发送数据）引脚需要连接到 MCU 的 RX（接收数据）引脚
#define UART_GPIO_PORT	GPIOA

/**
  * @brief 配置USART外设，包括：初始化引脚，初始化USART1外设，开启RXNE标志位中断等
  * @param 无
  * @retval 无
  */
void USART1_Config(void){
	// 1.开启 GPIOA 时钟 | 初始化 GPIO引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// - 配置USART_TX_Pin：说明书指定USART1输出引脚
	// - 模式：复用推挽输出模式
	//   - 复用：UART 的 TX 引脚属于外设功能，必须启用复用功能以连接到 UART 外设。
	//   - 推挽：推挽输出确保引脚能够稳定地驱动高电平和低电平，适合高速通信。
	//   - 输出：TX 引脚是发送端，必须配置为输出模式以主动发送数据。
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin = UART_TX_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;	
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(UART_GPIO_PORT, &GPIO_InitStruct);
	
	// - 配置USART_RX_Pin：说明书指定USART1输入引脚
	// - 模式：浮空输入模式
	GPIO_InitStruct.GPIO_Pin = UART_RX_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(UART_GPIO_PORT, &GPIO_InitStruct);
	
	// 2.开始 USART1外设 时钟 | 初始化 USART1外设
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	// - 配置 USART1外设
	USART_InitTypeDef USART_InitStruct;
	USART_InitStruct.USART_BaudRate = 115200;										// 波特率设置为115200
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 	// 不设置硬件流控
	USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;					// 设置为可收可发模式
	USART_InitStruct.USART_Parity = USART_Parity_No;								// 不设置验证位
	USART_InitStruct.USART_StopBits = USART_StopBits_1;								// 停止位为1位
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;						// 数据位为8位
	USART_Init(USART1, &USART_InitStruct);

    // - 使能开启 USART1外设
    USART_Cmd(USART1, ENABLE);		// 开启USART总开关

	// 3.开启 RXNE标志位中断
	// - 当 USART 接收到一个完整字节的数据时，硬件会自动将 RXNE 标志位置为 1
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	// 4.配置 NVIC
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;				// 开启 USART1中断
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;				// 开启 中断命令
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;		// 抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;				// 子优先级
	NVIC_Init(&NVIC_InitStruct);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  			// 2位抢占优先级，2位子优先级
}

/**
  * @brief 单片机向 PC 端发送字符串消息
  * @param 无
  * @retval 无
  */
void USART1_SendString(const char *Message){
	while(*Message){	// 遍历字符串直到遇到 '\0'
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);	// 等待发送寄存器为空（TXE 标志位为1）
	
		USART_SendData(USART1, *Message++);								// 发送当前字符
	}
}
